import axios from 'axios'
import { interceptorMiddle } from './utils/index'

// CancelToken模块
export default class CancelToken {
  _whiteList = [] // 白名单
  _requestMap = new Map() // 请求对照表（key：<path>， value：<cancelFun>）
  constructor(whiteList) {
    this._whiteList = [...this._whiteList, ...whiteList]
  }
  // 获取url的path（过滤掉查询参数和域名部分）
  getUrlPath(config) {
    let {url} = config
    if(url.toLowerCase().indexOf('http') !== -1)
      url = new URL(url).pathname
    return url.split('?')[0] // 不要查询参数部分
  }
  // 这里的config是axios拦截器处理后的，不是单纯用户传入的
  addPending(config) {
    const urlPath = this.getUrlPath(config)
    if(this._whiteList.includes(urlPath)) return // 白名单中不用取消 允许重复请求
    if(this._requestMap.has(urlPath)) {
      this.removePending(config) // 有正在发送的urlPath请求，就cancel掉
    }
    config.cancelToken = new axios.CancelToken(cancel => { // config参数带上CancelToken实例，后续即可取消请求
      this._requestMap.set(urlPath, cancel) // 设置进map
    })
  }
  // 请求成功/请求中产生重复请求 从map中删除对应请求的映射，并且调用一遍cancel
  removePending(config) {
    const urlPath = this.getUrlPath(config)
    if(this._requestMap.has(urlPath)) {
      this._requestMap.get(urlPath)(urlPath) // 执行cancel函数，传入cancel原因
      this._requestMap.delete(urlPath)
    }
  }
  // 清理掉所有映射 并 取消掉当前正在进行的所有请求
  clearPending() {
    for (const [urlPath, cancel] of this._requestMap) {
      cancel(urlPath)
    }
    this._requestMap.clear()
  }
  // axios拦截器封装，提供cancel层处理（参数中拦截器的type = undefined | [function, function]）
  enhanceInterceptor(requestInterceptors, responseInterceptors) {
    const defaultRequestInterceptors = [ // 默认 请求拦截器
      config => {
        this.addPending(config) // 内部已经处理取消prv重复请求
        return config
      },
      error => error // 方便拼接，相当于不做处理原样输出
    ]
    const defaultResponseInterceptors = [ // 默认响应拦截器
      response => {
        this.removePending(response.config)
        return response
      },
      // 响应错误，这部分预处理其实不太需要，因为addPending的时候有重复请求会自动调用removePending，因此只是为了方便测试逻辑
      error => {
        // this.removePending(response.config)
        return error
      }
    ]
    // const joint = (interceptors, defaultInterceptors) => {
    //   if(!interceptors) // undefined情况
    //     return defaultInterceptors
    //   else// [function, function] 作拼接 (传入的参数经过defaultInterceptors对应函数处理后再作为新的参数传入原拦截器函数)
    //     return [config => interceptors[0](defaultInterceptors[0](config)), error => interceptors[1](defaultInterceptors[1](error))]
    // }
    return [interceptorMiddle(requestInterceptors, defaultRequestInterceptors), interceptorMiddle(responseInterceptors, defaultResponseInterceptors)] // 增强后的请求&响应拦截器
  }
}